gl path "~/Dropbox/voter_id/Replication"

cap log close
log using "$path/table5.log", replace

use "$path/nc_dataset.dta" if new_reg == 0, clear

keep id election treat voted birth_year race_by_year age_by_year race_by_age_by_year ///
	no_dmv_match race_string


// replace voted with NA if under 18 / ineligible in that election year 
drop if birth_year > 1998 & birth_year < 9999
replace voted = . if (birth_year > 1990 & birth_year < 9999) & (election == 1 | election == 2) // 2008
replace voted = . if (birth_year > 1992 & birth_year < 9999) & (election == 3 | election == 4) // 2010
replace voted = . if (birth_year > 1994 & birth_year < 9999) & (election == 5 | election == 6) // 2012
replace voted = . if (birth_year > 1996 & birth_year < 9999) & (election == 7 | election == 8) // 2014

** create string encoding of possible pre-treatment outcome paths
tostring voted, generate(outcome_path)

by id: gen outcome_path_pretreat = outcome_path[1] + outcome_path[2] + ///
								outcome_path[3] + outcome_path[4] + ///
								outcome_path[5] + outcome_path[6] + ///
								outcome_path[7] + outcome_path[8] 

gen count = 1

// keep general only
keep if mod(election,2) == 0

replace voted = 0 if voted == .

// construct age bins, give young voters who are ineligible for some election their own age bin
gen age_bin = 11 if (birth_year > 1990 & birth_year < 9999)
replace age_bin = 12 if (birth_year > 1992 & birth_year < 9999)
replace age_bin = 13 if (birth_year > 1994 & birth_year < 9999)
replace age_bin = 14 if (birth_year > 1996 & birth_year < 9999)
// give those who are eligible over the whole period their own age decile
xtile age_decile = birth_year if (birth_year <= 1990), nq(10)
replace age_bin = age_decile if (birth_year <= 1990)
drop age_decile

sort id election

gen treat_2018 = treat * (election == 12)

compress


* vanilla diff in diff

reghdfe voted treat treat_2018, a(id election) cluster(id)
local b1 = _b[treat]
local se1 = _se[treat]
local b1_2 = _b[treat_2018]
local se1_2 = _se[treat_2018]
local n1 = e(N)
local nclust1 = e(N_clust)

* race by year
reghdfe voted treat treat_2018, a(id race_by_year) cluster(id)
local b2 = _b[treat]
local se2 = _se[treat]
local b2_2 = _b[treat_2018]
local se2_2 = _se[treat_2018]
local n2 = e(N)
local nclust2 = e(N_clust)

* age by year 
reghdfe voted treat treat_2018, a(id age_by_year) cluster(id)
local b3 = _b[treat]
local se3 = _se[treat]
local b3_2 = _b[treat_2018]
local se3_2 = _se[treat_2018]
local n3 = e(N)
local nclust3 = e(N_clust)

* age by race by year
reghdfe voted treat treat_2018, a(id race_by_age_by_year) cluster(id)
local b4 = _b[treat]
local se4 = _se[treat]
local b4_2 = _b[treat_2018]
local se4_2 = _se[treat_2018]
local n4 = e(N)
local nclust4 = e(N_clust)

// drop 2016 general, just want difference in means in 2018 general
drop if election == 10 

preserve

collapse (sum) count (mean) voted, by(outcome_path_pretreat no_dmv_match election)

*** get N by path by summing together n treated and n control
by outcome_path: gen tot_tmp = count[6] if _n==6
egen tot_treat = sum(tot_tmp), by(outcome_path)
by outcome_path: replace tot_tmp = count[1] if _n == 1
egen tot = sum(tot_tmp), by(outcome_path)
// N_voters is the number of voters who enter into the regression
egen N_voters = sum(tot_tmp)
// get number of elections
unique election
// N is number of voters * number of elections
gen long N = N_voters * r(unique)
drop tot_tmp
gen tot_control = tot - tot_treat

*** get weights for fw based on total n per stratum
*** each stratum has 10 obs
*** fw requires integers so need to round
gen tot2 = round(tot/10)
gen tot_treat2 = round(tot_treat/10)
egen op = group(outcome_path)

reghdfe voted no_dmv_match [fw=tot_treat2], a(op election)
local b5_2 = _b[no_dmv_match]
local se5_2 = _se[no_dmv_match]
local n5 = N
local nclust5 = N_voters


* match on pre-treatment turnout path and race

restore
preserve

collapse (sum) count (mean) voted, by(outcome_path_pretreat no_dmv_match election race_string)

*** get N by path by summing together n treated and n control
sort outcome_path race_string no_dmv_match
by outcome_path race_string: gen tot_tmp = count[6] if _n==6
egen tot_treat = sum(tot_tmp), by(outcome_path race_string)
by outcome_path race_string: replace tot_tmp = count[1] if _n == 1
egen tot = sum(tot_tmp), by(outcome_path race_string)
// N_voters is the number of voters who enter into the regression
egen N_voters = sum(tot_tmp)
// get number of elections
unique election
// N is number of voters * number of elections
gen long N = N_voters * r(unique)
drop tot_tmp
gen tot_control = tot - tot_treat

*** get weights for fw based on total n per stratum
*** each stratum has 10 obs
*** fw requires integers so need to round
gen tot2 = round(tot/10)
gen tot_treat2 = round(tot_treat/10)
egen op = group(outcome_path race_string)

reghdfe voted no_dmv_match [fw=tot_treat2], a(op election)
local b6 = _b[no_dmv_match]
local se6 = _se[no_dmv_match]
local b6_2 = _b[no_dmv_match]
local se6_2 = _se[no_dmv_match]
local n6 = N
local nclust6 = N_voters

restore

collapse (sum) count (mean) voted, by(outcome_path_pretreat no_dmv_match election race_string age_bin)

// drop if age is missing
drop if age_bin == .

*** get N by path by summing together n treated and n control
sort outcome_path race_string age_bin no_dmv_match election
by outcome_path race_string age_bin: gen tot_tmp = count[6] if _n==6
egen tot_treat = sum(tot_tmp), by(outcome_path race_string age_bin)
by outcome_path race_string age_bin: replace tot_tmp = count[1] if _n == 1
egen tot = sum(tot_tmp), by(outcome_path race_string age_bin)
// N_voters is the number of voters who enter into the regression
egen N_voters = sum(tot_tmp)
// get number of elections
unique election
// N is number of voters * number of elections
gen long N = N_voters * r(unique)
drop tot_tmp
gen tot_control = tot - tot_treat

*** get weights for fw based on total n per stratum
*** each stratum has 10 obs
*** fw requires integers so need to round
gen tot2 = round(tot/10)
gen tot_treat2 = round(tot_treat/10)
egen op = group(outcome_path race_string age_bin)

reghdfe voted no_dmv_match [fw=tot_treat2], a(op election)
local b7_2 = _b[no_dmv_match]
local se7_2 = _se[no_dmv_match]
local n7 = N 
local nclust7 = N_voters

log close

quietly {
	cap log close
	set linesize 255
	log using "$path/table5.tex", text replace
	
	noisily dis "\begin{table}[t]"
	noisily dis "\centering"
	noisily dis "\caption{\textbf{Effect of Voter ID Law on General Election Turnout Among Those Without ID, Individual Level, 2008--2018.}"
	noisily dis "\label{tab:voter_id_general_2018}}"
	noisily dis "\resizebox{\textwidth}{!} {"
	noisily dis "\begin{tabular}{lccccccc}"
	noisily dis "\toprule \toprule"
	noisily dis " & \multicolumn{7}{c}{Voted in General (0-1)}\\"
	noisily dis " & (1) & (2) & (3) & (4) & (5) & (6) & (7) \\"
	noisily dis "\midrule"
	noisily dis "No DMV Match * Year $\geq$ 2016 & " %4.3f `b1' " & " %4.3f `b2' " & " %4.3f `b3' " & " %4.3f `b4'  "\\"
	noisily dis " & (" %4.3f `se1' ") & (" %4.3f `se2' ") & (" %4.3f `se3' ") & (" %4.3f `se4' ")  \smallskip\\"

	noisily dis "No DMV Match * Year $\geq$ 2018 & " %4.3f `b1_2' " & " %4.3f `b2_2' " & " %4.3f `b3_2' " & " %4.3f `b4_2' " & " %4.3f `b5_2' " & " %4.3f `b6_2' " & " %4.3f `b7_2'  "\\"
	noisily dis " & (" %4.3f `se1_2' ") & (" %4.3f `se2_2' ") & (" %4.3f `se3_2' ") & (" %4.3f `se4_2' ") & (" %4.3f `se5_2' ") & (" %4.3f `se6_2' ") & (" %4.3f `se7_2' ") \smallskip\\"
	
	noisily dis " N & " %12.0fc `n1' " & " %12.0fc `n2' " & " %12.0fc `n3' " & " %12.0fc `n4' " & " %12.0fc `n5' " & " %12.0fc `n6' " & " %12.0fc `n7' " \\ "
	noisily dis " \# Voters & "  %12.0fc `nclust1' " & " %12.0fc `nclust2' " & " %12.0fc `nclust3' " & " %12.0fc `nclust4' " & " %12.0fc `nclust5' " & " %12.0fc `nclust6' " & " %12.0fc `nclust7' " \\ "
	
	noisily dis "Individual FEs & Y & Y & Y & Y & N & N & N \\"
	noisily dis "Year FEs & Y & N & N & N & Y & Y & Y  \\"
	noisily dis "Race by Year FEs & N & Y & N & N & N & N & N  \\"
	noisily dis "Age by Year FEs & N & N & Y & N & N & N & N \\"
	noisily dis "Race by Age by Year FEs & N & N & N & Y & N & N & N \\"
	noisily dis "Exact Match on Turnout & N & N & N & N & Y & Y & Y \\"
	noisily dis "Exact Match on Race & N & N & N & N & N & Y & Y \\"
	noisily dis "Exact Match on Age Bin & N & N & N & N & N & N & Y \\"
	noisily dis "\bottomrule \bottomrule"
	
	noisily dis "\multicolumn{8}{p{1.15\textwidth}}{\footnotesize Robust standard errors clustered by individual in parentheses.  Main effects for No DMV Match and 2016 are absorbed by fixed effects.  "
	noisily dis "Exact matching on turnout matches units based on each primary and general election from the 2008 primary through the 2014 general.  For exact matching on age, we construct a separate age bin for "
	noisily dis "each group of voters who were under 18 for a given set of elections, so the cohort of voters who became newly eligible to participate in 2010, 2012, 2014, and 2016 each have their own age bin.  "
	noisily dis "For voters who were eligible for all elections since 2008, we construct age deciles.}"
	
	noisily dis "\end{tabular}}"
	noisily dis "\end{table}"
	
	log off
	
}


